{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a8b892c8",
   "metadata": {},
   "source": [
    "Printed and electronic copies of *Modeling and Simulation in Python* are available from [No Starch Press](https://nostarch.com/modeling-and-simulation-python) and [Bookshop.org](https://bookshop.org/p/books/modeling-and-simulation-in-python-allen-b-downey/17836697?ean=9781718502161) and [Amazon](https://amzn.to/3y9UxNb)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "august-parks",
   "metadata": {},
   "source": [
    "# Rotation"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "imported-table",
   "metadata": {
    "tags": []
   },
   "source": [
    "*Modeling and Simulation in Python*\n",
    "\n",
    "Copyright 2021 Allen Downey\n",
    "\n",
    "License: [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International](https://creativecommons.org/licenses/by-nc-sa/4.0/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "formal-context",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# download modsim.py if necessary\n",
    "\n",
    "from os.path import basename, exists\n",
    "\n",
    "def download(url):\n",
    "    filename = basename(url)\n",
    "    if not exists(filename):\n",
    "        from urllib.request import urlretrieve\n",
    "        local, _ = urlretrieve(url, filename)\n",
    "        print('Downloaded ' + local)\n",
    "    \n",
    "download('https://raw.githubusercontent.com/AllenDowney/' +\n",
    "         'ModSimPy/master/modsim.py')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "progressive-typing",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# import functions from modsim\n",
    "\n",
    "from modsim import *"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "plastic-trigger",
   "metadata": {
    "tags": []
   },
   "source": [
    "This chapter is available as a Jupyter notebook where you can read the text, run the code, and work on the exercises. \n",
    "Click here to access the notebooks: <https://allendowney.github.io/ModSimPy/>."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "confirmed-california",
   "metadata": {},
   "source": [
    "In this chapter and the next we'll model systems that involve rotating objects.\n",
    "In general, rotation is complicated.\n",
    "In three dimensions, objects can rotate around three axes and many objects are easier to spin around some axes than others.\n",
    "If the configuration of an object changes over time, it might become\n",
    "easier or harder to spin, which explains the surprising dynamics of\n",
    "gymnasts, divers, ice skaters, etc.\n",
    "And when you apply a twisting force to a rotating object, the effect is often contrary to intuition. \n",
    "For an example, see this video on gyroscopic precession: <http://modsimpy.com/precess>."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "composed-carol",
   "metadata": {},
   "source": [
    "We will not take on the physics of rotation in all its glory; rather, we will focus on simple scenarios where all rotation and all twisting forces are around a single axis. \n",
    "In that case, we can treat some vector quantities as if they were scalars; that is, simple numbers.\n",
    "\n",
    "The fundamental ideas in these examples are angular velocity, angular acceleration, torque, and moment of inertia.\n",
    "If you are not already familiar with these concepts, don't worry; I will define them as we go along, and I will point to additional reading."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "integral-welsh",
   "metadata": {},
   "source": [
    "## The Physics of Toilet Paper\n",
    "\n",
    "As an example of a system with rotation, we'll simulate the manufacture of a roll of toilet paper, as shown in this video: <https://youtu.be/Z74OfpUbeac?t=231>. \n",
    "Starting with a cardboard tube at the center, we will roll up 47 m of paper, a typical length for a roll of toilet paper in the U.S. (see <http://modsimpy.com/paper>).\n",
    "\n",
    "The following figure shows a diagram of the system: $r$ represents\n",
    "the radius of the roll at a point in time. Initially, $r$ is the radius of the cardboard core, $R_{min}$. When the roll is complete, $r$ is $R_{max}$.\n",
    "\n",
    "![Diagram of a roll of toilet paper, showing change in paper length as a result of a small rotation, $d\\theta$.](https://github.com/AllenDowney/ModSim/raw/main/figs/paper_roll.png)\n",
    "\n",
    "I'll use $\\theta$ to represent the total rotation of the roll in radians. In the diagram, $d\\theta$ represents a small increase in $\\theta$, which corresponds to a distance along the circumference of $r~d\\theta$."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "political-prerequisite",
   "metadata": {},
   "source": [
    "I'll use $y$ to represent the total length of paper that's been rolled. \n",
    "Initially, $\\theta=0$ and $y=0$. \n",
    "For each small increase in $\\theta$, there is a corresponding increase in $y$: \n",
    "\n",
    "$$dy = r~d\\theta$$\n",
    "\n",
    "If we divide both sides by a small increase in time, $dt$, we get a\n",
    "differential equation for $y$ as a function of time.\n",
    "\n",
    "$$\\frac{dy}{dt} = r \\frac{d\\theta}{dt}$$ \n",
    "\n",
    "As we roll up the paper, $r$ increases. Assuming it increases by a fixed amount per revolution, we can write \n",
    "\n",
    "$$dr = k~d\\theta$$ \n",
    "\n",
    "where $k$ is an unknown constant we'll have to figure out. \n",
    "Again, we can divide both sides by $dt$ to get a differential equation in time:\n",
    "\n",
    "$$\\frac{dr}{dt} = k \\frac{d\\theta}{dt}$$ \n",
    "\n",
    "Finally, let's assume that $\\theta$ increases at a constant rate of $\\omega = 300$ rad/s (about 2900 revolutions per minute): \n",
    "\n",
    "$$\\frac{d\\theta}{dt} = \\omega$$ \n",
    "\n",
    "This rate of change is called an *angular velocity*. Now we have a system of differential equations we can use to simulate the system."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "prostate-smell",
   "metadata": {},
   "source": [
    "## Setting Parameters\n",
    "\n",
    "Here are the parameters of the system:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "honey-translator",
   "metadata": {},
   "outputs": [],
   "source": [
    "Rmin = 0.02      # m\n",
    "Rmax = 0.055     # m\n",
    "L = 47           # m\n",
    "omega = 300      # rad / s"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "provincial-logistics",
   "metadata": {},
   "source": [
    "`Rmin` and `Rmax` are the initial and final values for the radius, `r`.\n",
    "`L` is the total length of the paper.\n",
    "`omega` is the angular velocity in radians per second.\n",
    "\n",
    "Figuring out `k` is not easy, but we can estimate it by pretending that `r` is constant and equal to the average of `Rmin` and `Rmax`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "floppy-plane",
   "metadata": {},
   "outputs": [],
   "source": [
    "Ravg = (Rmax + Rmin) / 2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ordinary-leader",
   "metadata": {},
   "source": [
    "In that case, the circumference of the roll is also constant:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "funky-bandwidth",
   "metadata": {},
   "outputs": [],
   "source": [
    "Cavg = 2 * np.pi * Ravg"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "square-radius",
   "metadata": {},
   "source": [
    "And we can compute the number of revolutions to roll up length `L`, like this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "front-conservation",
   "metadata": {},
   "outputs": [],
   "source": [
    "revs = L / Cavg"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "headed-gibson",
   "metadata": {},
   "source": [
    "Converting rotations to radians, we can estimate the final value of `theta`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "defined-plymouth",
   "metadata": {},
   "outputs": [],
   "source": [
    "theta = 2 * np.pi * revs\n",
    "theta"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "naughty-narrative",
   "metadata": {},
   "source": [
    "Finally, `k` is the total change in `r` divided by the total change in `theta`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "subject-brief",
   "metadata": {},
   "outputs": [],
   "source": [
    "k_est = (Rmax - Rmin) / theta\n",
    "k_est"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "experienced-sharing",
   "metadata": {},
   "source": [
    "At the end of the chapter, we'll derive `k` analytically, but this estimate is enough to get started."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "phantom-yacht",
   "metadata": {},
   "source": [
    "## Simulating the System\n",
    "\n",
    "The state variables we'll use are `theta`, `y`, and `r`.\n",
    "Here are the initial conditions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "ranging-graham",
   "metadata": {},
   "outputs": [],
   "source": [
    "init = State(theta=0, y=0, r=Rmin)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "caring-unemployment",
   "metadata": {},
   "source": [
    "And here's a `System` object with `init` and `t_end`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "fresh-domestic",
   "metadata": {},
   "outputs": [],
   "source": [
    "system = System(init=init, t_end=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "beginning-artwork",
   "metadata": {},
   "source": [
    "Now we can use the differential equations from the previous section to\n",
    "write a slope function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "signed-eight",
   "metadata": {},
   "outputs": [],
   "source": [
    "def slope_func(t, state, system):\n",
    "    theta, y, r = state\n",
    "    \n",
    "    dydt = r * omega\n",
    "    drdt = k_est * omega\n",
    "    \n",
    "    return omega, dydt, drdt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "maritime-funds",
   "metadata": {},
   "source": [
    "As usual, the slope function takes a time stamp, a `State` object, and a `System` object. \n",
    "\n",
    "The job of the slope function is to compute the time derivatives of the state variables.\n",
    "The derivative of `theta` is angular velocity, `omega`.\n",
    "The derivatives of `y` and `r` are given by the differential equations we derived."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "trained-witness",
   "metadata": {},
   "source": [
    "And as usual, we'll test the slope function with the initial conditions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "exterior-water",
   "metadata": {},
   "outputs": [],
   "source": [
    "slope_func(0, system.init, system)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "russian-rochester",
   "metadata": {},
   "source": [
    "We'd like to stop the simulation when the length of paper on the roll is `L`. We can do that with an event function that passes through 0 when `y` equals `L`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "strong-custody",
   "metadata": {},
   "outputs": [],
   "source": [
    "def event_func(t, state, system):\n",
    "    theta, y, r = state\n",
    "    return L - y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "catholic-workshop",
   "metadata": {},
   "source": [
    "We can test it with the initial conditions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "moved-present",
   "metadata": {},
   "outputs": [],
   "source": [
    "event_func(0, system.init, system)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "affecting-pathology",
   "metadata": {},
   "source": [
    "Now let's run the simulation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "stable-lying",
   "metadata": {},
   "outputs": [],
   "source": [
    "results, details = run_solve_ivp(system, slope_func,\n",
    "                                  events=event_func)\n",
    "details.message"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "experienced-pathology",
   "metadata": {},
   "source": [
    "Here are the last few time steps."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "careful-bahrain",
   "metadata": {},
   "outputs": [],
   "source": [
    "results.tail()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "underlying-variance",
   "metadata": {},
   "source": [
    "The time it takes to complete one roll is about 4.2 seconds, which is consistent with what we see in the video."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "individual-patrick",
   "metadata": {},
   "outputs": [],
   "source": [
    "results.index[-1]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "informative-porter",
   "metadata": {},
   "source": [
    "The final value of `y` is 47 meters, as expected."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "indian-skirt",
   "metadata": {},
   "outputs": [],
   "source": [
    "final_state = results.iloc[-1] \n",
    "final_state.y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "running-tutorial",
   "metadata": {},
   "source": [
    "The final value of `r` is 0.55 m, which is `Rmax`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "higher-conflict",
   "metadata": {},
   "outputs": [],
   "source": [
    "final_state.r"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "tamil-referral",
   "metadata": {},
   "source": [
    "The total number of rotations is close to 200, which seems plausible."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "employed-ordinary",
   "metadata": {},
   "outputs": [],
   "source": [
    "radians = final_state.theta\n",
    "rotations = radians / 2 / np.pi\n",
    "rotations"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "otherwise-mississippi",
   "metadata": {},
   "source": [
    "As an exercise, we'll see how fast the paper is moving.  But first, let's take a closer look at the results."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "lesser-consumer",
   "metadata": {},
   "source": [
    "## Plotting the Results\n",
    "\n",
    "Here's what `theta` looks like over time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "included-schema",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_theta(results):\n",
    "    results.theta.plot(color='C0', label='theta')\n",
    "    decorate(xlabel='Time (s)',\n",
    "             ylabel='Angle (rad)')\n",
    "    \n",
    "plot_theta(results)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "regulation-runner",
   "metadata": {},
   "source": [
    "`theta` grows linearly, as we should expect with constant angular velocity.\n",
    "\n",
    "Here's what `r` looks like over time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "persistent-siemens",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_r(results):\n",
    "    results.r.plot(color='C2', label='r')\n",
    "\n",
    "    decorate(xlabel='Time (s)',\n",
    "             ylabel='Radius (m)')\n",
    "    \n",
    "plot_r(results)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "smoking-spine",
   "metadata": {},
   "source": [
    "`r` also increases linearly.\n",
    "\n",
    "Here's what `y` looks like over time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "contrary-typing",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_y(results):\n",
    "    results.y.plot(color='C1', label='y')\n",
    "\n",
    "    decorate(xlabel='Time (s)',\n",
    "             ylabel='Length (m)')\n",
    "    \n",
    "plot_y(results)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dedicated-tuning",
   "metadata": {},
   "source": [
    "Since the derivative of `y` depends on `r`, and `r` is increasing, `y` grows with increasing slope.\n",
    "\n",
    "In the next section, we'll see that we could have solved these differential equations analytically.\n",
    "However, it is often useful to start with simulation as a way of exploring and checking assumptions."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "better-asbestos",
   "metadata": {},
   "source": [
    "## Analytic Solution\n",
    "\n",
    "Since angular velocity is constant: \n",
    "\n",
    "$$\\frac{d\\theta}{dt} = \\omega \\quad\\quad (1)$$ \n",
    "\n",
    "We can find $\\theta$ as a function of time by integrating both sides:\n",
    "\n",
    "$$\\theta(t) = \\omega t$$ \n",
    "\n",
    "Similarly, we can solve this equation\n",
    "\n",
    "$$\\frac{dr}{dt} = k \\omega$$\n",
    "\n",
    "to find\n",
    "\n",
    "$$r(t) = k \\omega t + R_{min}$$ \n",
    "\n",
    "Then we can plug the solution for $r$ into the equation for $y$: \n",
    "\n",
    "$$\\begin{aligned}\n",
    "\\frac{dy}{dt} & = r \\omega        \\quad\\quad (2)              \\\\\n",
    "              & = \\left[ k \\omega t + R_{min} \\right] \\omega \\nonumber\\end{aligned}$$\n",
    "              \n",
    "Integrating both sides yields:\n",
    "\n",
    "$$y(t) = \\left[ k \\omega t^2 / 2 + R_{min} t \\right] \\omega$$ \n",
    "\n",
    "So $y$ is a parabola, as you might have guessed."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "meaningful-kazakhstan",
   "metadata": {},
   "source": [
    "We can also use these equations to find the relationship between $y$ and $r$, independent of time, which we can use to compute $k$.\n",
    "Dividing Equations 1 and 2 yields\n",
    "\n",
    "$$\\frac{dr}{dy} = \\frac{k}{r}$$ \n",
    "\n",
    "Separating variables yields\n",
    "\n",
    "$$r~dr = k~dy$$ \n",
    "\n",
    "Integrating both sides yields \n",
    "\n",
    "$$r^2 / 2 = k y + C$$ \n",
    "\n",
    "Solving for $y$, we have \n",
    "\n",
    "$$y = \\frac{1}{2k} (r^2 - C)                 \\label{eqn3}$$\n",
    "\n",
    "When $y=0$, $r=R_{min}$, so \n",
    "\n",
    "$$R_{min}^2 / 2 = C$$ \n",
    "\n",
    "When $y=L$, $r=R_{max}$, so\n",
    "\n",
    "$$L = \\frac{1}{2k} (R_{max}^2 - R_{min}^2)$$ \n",
    "\n",
    "Solving for $k$ yields\n",
    "\n",
    "$$k =  \\frac{1}{2L} (R_{max}^2 - R_{min}^2)           \\label{eqn4}$$\n",
    "\n",
    "Plugging in the values of the parameters yields `2.8e-5` m/rad, the same as the \"estimate\" we computed in Section xxx. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "acknowledged-register",
   "metadata": {},
   "outputs": [],
   "source": [
    "k = (Rmax**2 - Rmin**2) / (2 * L)\n",
    "k"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "retired-skill",
   "metadata": {},
   "source": [
    "In this case the estimate turns out to be exact."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "foreign-needle",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "This chapter introduces rotation, starting with an example where angular velocity is constant.\n",
    "We simulated the manufacture of a roll of toilet paper, then we solved the same problem analytically.\n",
    "\n",
    "In the next chapter, we'll see a more interesting example where angular velocity is not constant.  And we'll introduce three new concepts: torque, angular acceleration, and moment of inertia.\n",
    "\n",
    "But first, you might want to work on the following exercise."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "variable-lambda",
   "metadata": {},
   "source": [
    "## Exercises\n",
    "\n",
    "This chapter is available as a Jupyter notebook where you can read the text, run the code, and work on the exercises. \n",
    "You can access the notebooks at <https://allendowney.github.io/ModSimPy/>."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "thick-luther",
   "metadata": {},
   "source": [
    "### Exercise 1\n",
    "\n",
    " Since we keep `omega` constant, the linear velocity of the paper increases with radius.  We can use `gradient` to estimate the derivative of `results.y`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "cardiac-hospital",
   "metadata": {},
   "outputs": [],
   "source": [
    "dydt = gradient(results.y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "atomic-montana",
   "metadata": {},
   "source": [
    "Here's what the result looks like."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "welsh-charleston",
   "metadata": {},
   "outputs": [],
   "source": [
    "dydt.plot(label='dydt')\n",
    "decorate(xlabel='Time (s)',\n",
    "         ylabel='Linear velocity (m/s)')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "becoming-birthday",
   "metadata": {},
   "source": [
    "With constant angular velocity, linear velocity is increasing, reaching its maximum at the end."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "informational-washer",
   "metadata": {},
   "outputs": [],
   "source": [
    "max_linear_velocity = dydt.iloc[-1]\n",
    "max_linear_velocity"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bizarre-variation",
   "metadata": {},
   "source": [
    "Now suppose this peak velocity is the limiting factor; that is, we can't move the paper any faster than that.\n",
    "In that case, we might be able to speed up the process by keeping the linear velocity at the maximum all the time.\n",
    "\n",
    "Write a slope function that keeps the linear velocity, `dydt`, constant, and computes the angular velocity, `omega`, accordingly.\n",
    "Then, run the simulation and see how much faster we could finish rolling the paper."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "excellent-japanese",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "steady-member",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "applied-sacramento",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "adult-chuck",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "conditional-cliff",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "arranged-queensland",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "similar-variance",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Solution goes here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "lovely-orange",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
